<?php

use app\common\model\SystemConfig;
use support\Cache;
use Webman\Route;
use GuzzleHttp\Client;

/**
 * 发送HTTP请求
 * @param string $url 请求URL
 * @param array $params 请求参数
 * @param string $method 请求方法 GET/POST/PUT/DELETE
 * @param array $headers 请求头
 * @return array 响应数据
 * @throws \Exception
 */
function httpRequest($url, $params = [], $method = 'GET', $headers = [])
{
    $headers = array_merge([
        'Accept'       => 'application/json',
        'Content-Type' => 'application/json',
        'User-Agent'   => 'ServiceProject/1.0',
    ], $headers);

    $client = new Client([
        'timeout' => 30,
        'verify'  => false,          // 如需跳过证书
        'headers' => $headers,
    ]);

    $resp = $client->request($method, $url, [
        $method === 'GET' ? 'query' : 'json' => $params,
    ]);
    $data = json_decode($resp->getBody(), true);

    if (json_last_error() !== JSON_ERROR_NONE) {
        throw new \Exception('Bad JSON: ' . json_last_error_msg());
    }

    return $data;
}

/**
 * 阅读量格式化 保留2位小数
 * @param int $num 需要格式化的数字
 * @return string 格式化后的数字
 */
function format_view_count($num)
{
    if ($num >= 10000) {
        return number_format($num / 10000, 2) . 'W+';
    } else if ($num >= 1000) {
        return number_format($num / 1000, 2) . 'K+';
    } else {
        return $num;
    }
}

/**
 * 获取输入参数 支持默认值和过滤
 * @param string $name 变量名
 * @param mixed  $default 默认值
 * @return mixed
 */
if (!function_exists('inputs')) {
    function inputs(string $name, $default = null)
    {
        $type = null;

        if (strpos($name, '/') !== false) {
            [$name, $type] = explode('/', $name);
        }

        $value = request()->input($name, $default);

        // 处理类型转换
        if ($type && in_array($type, ['d', 'a', 'f', 's'])) {
            $value   = convert_type($value, $type);
            $default = convert_type($default, $type);
        }

        return $value;
    }
}

/**
 * 根据类型标识转换值的类型
 * @param mixed $value 需要转换的值
 * @param string $type 类型标识 d:整数 a:数组 f:浮点数 s:字符串
 * @return mixed 转换后的值
 */
if (!function_exists('convert_type')) {
    function convert_type($value, string $type)
    {
        switch ($type) {
            case 'd':
                return intval($value);
            case 'a':
                return (array) $value;
            case 'f':
                return floatval($value);
            case 's':
                return strval($value);
            default:
                return $value;
        }
    }
}

/**
 * 设备或配置系统参数或者新增系统参数
 * @param string $name  参数名称
 * @param $value 默认是null为获取值，否则为更新
 * @return string|bool|array
 */
function conf($name, $value = null)
{
    if (is_null($value)) {
        // 模型查询 用于被BaseModel的onAfterRead事件拦截
        // 优先从缓存中获取
        $cache = Cache::get('system_config_' . $name);
        if ($cache) {
            return $cache;
        }
        $res   = SystemConfig::where('name', $name)->find();
        $value = $res ? $res->value : '';
        // 如果是数字，转换成数字
        if (is_numeric($value)) {
            $value = $value + 0;
        }
        // 如果是 JSON
        $json = json_decode($value, true);
        if (json_last_error() == JSON_ERROR_NONE) {
            $value = $json;
        }
        // 缓存
        Cache::set('system_config_' . $name, $value);
        return $value;
    } else {
        // 删除缓存
        Cache::delete('system_config_' . $name);
        // 如果$value是数组或者对象，转换成json
        if (is_array($value) || is_object($value)) {
            $value = json_encode($value, JSON_UNESCAPED_UNICODE);
        }
        $res = SystemConfig::where('name', $name)->find();
        // 如果存在则更新配置
        if ($res) {
            $res->value = $value;
            // 如果是切换运行模式 则 重载服务
            if ($name == 'app_site_mode') {
                reload_webman();
            }
            $res->save();
        } else {
            // 如果不存在则新增配置
            SystemConfig::create(['name' => $name, 'value' => $value]);
        }
        return true;
    }
}

/**
 * 生成订单号
 * @param string $flag 订单标识
 * @param int    $userid 用户id
 * @return string 订单号
 */
function generate_trade_no($flag = 'A')
{

    $trade_no = $flag . date('ymdHis') . str_pad(10000, 4, 0) . str_pad(mt_rand(0, 99), 2, '0');

    //校验是否有重复订单号
    $res = \app\common\model\OrderMaster::where([
        'trade_no' => $trade_no
    ])->find();
    if (!empty($res)) {
        //需要重新生成订单号
        $trade_no = generate_trade_no($flag);
    }

    return $trade_no;
}

/**
 * xxs过滤
 * @param mixed $param
 * @param bool $filter
 * @return mixed
 */
function param_filter($param, bool $filter = true)
{
    if (!$param || !$filter || !is_string($param)) {
        return $param;
    }
    $param       = htmlspecialchars_decode($param);
    $filter_rule = [
        "/<(\\/?)(script|style|html|body|title|link|meta|object|\\?|\\%)([^>]*?)>/isU",
        "/(<[^>]*)on[a-zA-Z]+\s*=([^>]*>)/isU",
        "/select|join|where|drop|like|modify|rename|insert|update|table|database|alter|truncate|\'|\/\*|\.\.\/|\.\/|union|into|load_file|outfile/is"
    ];
    return preg_replace($filter_rule, '', $param);
}

/**
 * 获取文本内容中的图片并返回图片数组
 * @param string $content 文本内容
 * @return array 图片数组
 */
function get_images_from_content($content)
{
    $images  = [];
    $pattern = '/<img[^>]+src="([^"]+\.(jpg|jpeg|png|gif))"[^>]*>/i';
    preg_match_all($pattern, $content, $matches);
    if (isset($matches[1])) {
        $images = $matches[1];
    }
    return $images;
}

/**
 * 获取图片数组中的第一个图片
 * @param string $content 文本内容
 * @return string 图片url
 */
function get_first_image_from_content($content)
{
    $images = get_images_from_content($content);
    return $images[0] ?? '';
}

/**
 * 格式化文件大小
 * @param int $size 文件大小（字节B）
 * @param int $decimals 小数位数
 * @return string 格式化后的文件大小，如 1.5 KB、2.3 MB、1.1 GB 等
 */
function format_file_size($size, $decimals = 2)
{
    if ($size <= 0) {
        return '0 B';
    }

    $units  = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
    $factor = floor((strlen((string) $size) - 1) / 3);

    // 计算并格式化大小
    $formatted_size = $size / pow(1024, $factor);

    // 如果小于1000且为整数，则不显示小数
    if ($formatted_size < 1000 && floor($formatted_size) == $formatted_size) {
        return sprintf("%d %s", $formatted_size, $units[$factor]);
    }

    // 如果结果是整数，不显示小数位
    if (floor($formatted_size) == $formatted_size) {
        return sprintf("%d %s", $formatted_size, $units[$factor]);
    }

    // 去除小数末尾的0
    $formatted_size = floatval(sprintf("%.{$decimals}f", $formatted_size));

    return sprintf("%.{$decimals}f %s", $formatted_size, $units[$factor]);
}

/**
 * 格式化秒数为易读时间格式
 * @param int $seconds 秒数
 * @param string $format 格式类型，可选：'colon'（冒号分隔，如01:30:45）, 'text'（文字，如1小时30分钟）, 'short'（简短，如1h30m）
 * @param bool $show_seconds 是否显示秒数
 * @return string 格式化后的时间字符串
 */
function format_seconds($seconds, $format = 'colon', $show_seconds = true)
{
    if (!is_numeric($seconds) || $seconds < 0) {
        return '00:00';
    }

    $seconds = (int) $seconds;
    $hours   = floor($seconds / 3600);
    $minutes = floor(($seconds % 3600) / 60);
    $secs    = $seconds % 60;

    switch ($format) {
        case 'text':
            $result = '';
            if ($hours > 0) {
                $result .= $hours . '小时';
            }
            if ($minutes > 0 || ($hours > 0 && $secs > 0)) {
                $result .= $minutes . '分钟';
            }
            if ($show_seconds && ($secs > 0 || empty($result))) {
                $result .= $secs . '秒';
            }
            return $result;

        case 'short':
            $result = '';
            if ($hours > 0) {
                $result .= $hours . 'h';
            }
            if ($minutes > 0 || ($hours > 0 && $secs > 0)) {
                $result .= $minutes . 'm';
            }
            if ($show_seconds && ($secs > 0 || empty($result))) {
                $result .= $secs . 's';
            }
            return $result;

        case 'colon':
        default:
            if ($hours > 0) {
                $format = '%02d:%02d:%02d';
                return sprintf($format, $hours, $minutes, $secs);
            } else {
                if ($show_seconds) {
                    return sprintf('%02d:%02d', $minutes, $secs);
                } else {
                    return sprintf('%02d分钟', $minutes);
                }
            }
    }
}

/**
 * 获取路由url
 * @param string $name 路由名称
 * @param array $parameters 参数
 * @return string 路由url
 */
function _url_($name, $parameters = [])
{
    $route = Route::getByName($name);
    if (!$route) {
        return '';
    }
    return $route->url($parameters);
}

// ============================================================================
// 插件系统 - 基于webman事件系统
// ============================================================================

/**
 * Hook函数 - 零I/O开销的钩子系统
 * @param string $hook_name 钩子名称
 * @param mixed $params 传递给钩子的参数
 * @param string $type 类型 默认输出器 / 过滤器 filter
 * @return mixed 钩子执行结果
 */
function hook($hook_name, $params = null, $type = 'out')
{
    // 转换钩子名称为事件名称
    $event_name = str_replace('_', '.', $hook_name);

    $result = \app\common\plugin\HookRegistry::executeHook($event_name, $params);
    if ($type == 'out') {
        // 确保返回字符串，用于模板输出
        if (is_array($result)) {
            return implode('', $result);
        } elseif (is_string($result)) {
            return $result;
        } else {
            return '';
        }
    } else {
        return $result;
    }

}

/**
 * 获取启用的插件列表
 * @return array
 */
function get_enabled_plugins()
{
    static $plugins = null;
    if ($plugins === null) {
        $plugins     = [];
        $plugins_dir = base_path() . '/plugins';
        if (!is_dir($plugins_dir)) {
            return $plugins;
        }

        $dirs = scandir($plugins_dir);
        foreach ($dirs as $dir) {
            if ($dir === '.' || $dir === '..') {
                continue;
            }

            $plugin_path = $plugins_dir . '/' . $dir;
            $info_file   = $plugin_path . '/info.ini';

            if (is_dir($plugin_path) && file_exists($info_file)) {
                $info = parse_ini_file($info_file);
                if ($info && isset($info['status']) && $info['status'] == 1) {
                    $plugins[] = $dir;
                }
            }
        }
    }
    return $plugins;
}

/**
 * 检查插件是否启用
 * @param string $plugin_name 插件名称
 * @return bool
 */
function is_plugin_enabled($plugin_name)
{
    return in_array($plugin_name, get_enabled_plugins());
}

/**
 * 获取插件路径
 * @param string $plugin_name 插件名称
 * @return string
 */
function get_plugin_path($plugin_name)
{
    return base_path() . '/plugins/' . $plugin_name;
}

/**
 * 获取插件配置
 * @param string $plugin_name 插件名称
 * @return array
 */
function get_plugin_config($plugin_name)
{
    $plugin_path = get_plugin_path($plugin_name);
    $config_file = $plugin_path . '/config.php';

    if (!file_exists($config_file)) {
        return [];
    }

    return require $config_file;
}

/**
 * 重载 webman 服务
 * 用于插件配置更改后自动重启
 */
function reload_webman()
{
    try {
        // 获取 webman 根目录
        $webman_root = base_path();
        // 检查是否在正确的目录
        if (!file_exists($webman_root . '/webman')) {
            \support\Log::channel('plugin')->error("Webman 重启失败：找不到 webman 可执行文件");
            return false;
        }
        // 异步执行重启命令，避免阻塞当前请求
        $command = "cd {$webman_root} && php webman reload > /dev/null 2>&1 &";
        // 执行命令
        exec($command, $output, $return_code);
        return true;
    } catch (\Exception $e) {
        return false;
    }
}

/**
 * 获取插件静态资源URL
 * @param string $plugin_name 插件名称
 * @param string $file_path 文件路径（相对于插件public目录）
 * @return string
 */
function plugin_static_url($plugin_name, $file_path)
{
    return "/plugins/{$plugin_name}/" . ltrim($file_path, '/');
}

/**
 * 插件视图渲染函数
 * @param string $template 模板路径（相对于插件view目录）
 * @param array $vars 模板变量
 * @param string $plugin_name 插件名称
 * @return \Webman\Http\Response
 */
function plugin_view($template, $vars = [], $plugin_name = null)
{
    // 如果没有指定插件名称，尝试从请求中获取
    if ($plugin_name === null) {
        $request = request();
        $path    = $request->path();

        // 从路径中解析插件名称 /plugin/blog-comment/test/index
        if (preg_match('#^/plugin/([^/]+)/#', $path, $matches)) {
            $plugin_name = str_replace('-', '_', $matches[1]);
        }
    }

    if (!$plugin_name) {
        throw new \Exception('Plugin name not found');
    }

    // 检测插件是否开启
    if (!is_plugin_enabled($plugin_name)) {
        throw new \Exception('Plugin not enabled');
    }

    // 构建插件模板路径
    $plugin_path   = get_plugin_path($plugin_name);
    $template_file = $plugin_path . '/view/' . $template;

    // 检查模板文件是否存在
    if (!file_exists($template_file . '.html')) {
        throw new \Exception("Plugin template not found: {$template_file}.html");
    }

    // 使用ThinkPHP模板引擎渲染
    $handler = \config('view.handler');

    // 设置插件模板路径
    $viewPath = $plugin_path . '/view/';
    $options  = [
        'view_path'   => $viewPath,
        'cache_path'  => runtime_path() . '/views/',
        'view_suffix' => 'html'
    ];

    $views = new \think\Template($options);
    ob_start();
    $views->fetch($template, $vars);
    $content = ob_get_clean();

    return new \Webman\Http\Response(200, [], $content);
}
